using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.Media3D;
using SharpGL.Enumerations;

namespace SharpGL.OpenGLAttributes
{
    /// <summary>
    /// This class has all the settings you can edit for texture.
    /// </summary>
    [TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
    [DataContract(/*IsReference = true, */Name = "TextureAttributes", Namespace = "SharpGL.SceneGraph")]
    public class TextureAttributes : OpenGLAttributes
    {
        #region Private Consts

        private static readonly AttributeMask attributeMask = AttributeMask.Texture;

        #endregion Private Consts

        #region Private Fields

        [DataMember()]
        private TextureTarget? textureTarget;
        [DataMember()]
        private TextureMagFilter? textureMagFilter;
        [DataMember()]
        private TextureMinFilter? textureMinFilter;
        [DataMember()]
        private TextureWrap? textureWrapS;
        [DataMember()]
        private TextureWrap? textureWrapT;
        [DataMember()]
        private GLColor? textureBorderColor;

        #endregion Private Fields

        #region Protected Methods

        protected override void OnDeserializing()
        {
            AttributeFlags = attributeMask;
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="TextureAttributes"/> class.
        /// </summary>
        public TextureAttributes()
        {
            AttributeFlags = attributeMask;

            /*TODO
             Enable bits for the four texture coordinates

            Color and mode for each texture environment

            Enable bits GL_TEXTURE_GEN_x; x is S, T, R, and Q

            GL_TEXTURE_GEN_MODE setting for S, T, R, and Q

            glTexGen plane equations for S, T, R, and Q*/
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Returns true if any attributes are set.
        /// </summary>
        /// <returns>
        /// True if any attributes are set
        /// </returns>
        public override bool AreAnyAttributesSet()
        {
            return textureTarget.HasValue ||
                textureMagFilter.HasValue ||
                textureMinFilter.HasValue ||
                textureWrapS.HasValue ||
                textureWrapT.HasValue ||
                textureBorderColor.HasValue;
        }

        /// <summary>
        /// Reset all attributes to unset state.
        /// </summary>
        public override void ResetAllAttributes()
        {
            textureTarget = null;
            textureMinFilter = null;
            textureMagFilter = null;
            textureWrapS = null;
            textureWrapT = null;
            textureBorderColor = null;
        }

        /// <summary>
        /// Sets the attributes.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        public override void SetAttributes(OpenGL gl)
        {
            if (textureTarget.HasValue && textureMinFilter.HasValue) gl.TexParameter(textureTarget.Value, TextureParameter.TextureMinFilter, (int)textureMinFilter.Value);
            if (textureTarget.HasValue && textureMagFilter.HasValue) gl.TexParameter(textureTarget.Value, TextureParameter.TextureMagFilter, (int)textureMagFilter.Value);
            if (textureTarget.HasValue && textureWrapS.HasValue) gl.TexParameter(textureTarget.Value, TextureParameter.TextureWrapS, (int)textureWrapS.Value);
            if (textureTarget.HasValue && textureWrapT.HasValue) gl.TexParameter(textureTarget.Value, TextureParameter.TextureWrapT, (int)textureWrapT.Value);
            if (textureTarget.HasValue && textureBorderColor.HasValue) gl.TexParameter(textureTarget.Value, TextureParameter.TextureBorderColor, textureBorderColor.Value);
        }

        #endregion Public Methods

        #region Public Properties

        [Description("The target texture for use all parameters"), Category("Texture attributes")]
        public TextureTarget? TextureTarget
        {
            get { return textureTarget; }
            set
            {
                if (textureTarget != value)
                {
                    textureTarget = value;

                    NotifyPropertyChanged("TextureTarget");
                }
            }
        }

        [Description("The texture minifying function"), Category("Texture attributes")]
        public TextureMinFilter? TextureMinFilter
        {
            get { return textureMinFilter; }
            set
            {
                if (textureMinFilter != value)
                {
                    textureMinFilter = value;

                    NotifyPropertyChanged("TextureMinFilter");
                }
            }
        }

        [Description("The texture magnification function"), Category("Texture attributes")]
        public TextureMagFilter? TextureMagFilter
        {
            get { return textureMagFilter; }
            set
            {
                if (textureMagFilter != value)
                {
                    textureMagFilter = value;

                    NotifyPropertyChanged("TextureMagFilter");
                }
            }
        }

        [Description("The wrap parameter for texture coordinate S"), Category("Texture attributes")]
        public TextureWrap? TextureWrapS
        {
            get { return textureWrapS; }
            set
            {
                if (textureWrapS != value)
                {
                    textureWrapS = value;

                    NotifyPropertyChanged("TextureWrapS");
                }
            }
        }

        [Description("The wrap parameter for texture coordinate T"), Category("Texture attributes")]
        public TextureWrap? TextureWrapT
        {
            get { return textureWrapT; }
            set
            {
                if (textureWrapT != value)
                {
                    textureWrapT = value;

                    NotifyPropertyChanged("TextureWrapT");
                }
            }
        }

        [Description("A border color"), Category("Texture attributes")]
        public GLColor? TextureBorderColor
        {
            get { return textureBorderColor; }
            set
            {
                if (textureBorderColor != value)
                {
                    textureBorderColor = value;

                    NotifyPropertyChanged("TextureBorderColor");
                }
            }
        }

        #endregion Public Properties
    }
}
